/*
 * Triangle2D.h
 *
 *  Created on: 2009/01/23
 *      Author: Yongshik Cho
 */

#ifndef TRIANGLE2D_H_
#define TRIANGLE2D_H_

#include "Math3D.h"

#ifndef LINE2D_H_
#	include "Line2D.h"
#endif

class Triangle2D : public Collidable
{
public:
	Triangle2D(uint32 type = Collidable::COLLIDABLE_TRIANGLE) :
		Collidable(type)
	{
		mPoints.clear();
		mPoints.push_back(Vector2D(0.f, 0.f));
		mPoints.push_back(Vector2D(0.f, 0.f));
		mPoints.push_back(Vector2D(0.f, 0.f));

		mClosed = true;
	}
	Triangle2D(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3, uint32 type = Collidable::COLLIDABLE_TRIANGLE) :
		Collidable(type)
	{
		mPoints.clear();
		mPoints.push_back(p1);
		mPoints.push_back(p2);
		mPoints.push_back(p3);

		mClosed = true;
	}
	Triangle2D(const Triangle2D& rhs, uint32 type = Collidable::COLLIDABLE_TRIANGLE) :
		Collidable(type)
	{
		mPoints.clear();
		mPoints.push_back(rhs.mPoints[0]);
		mPoints.push_back(rhs.mPoints[1]);
	}

	virtual ~Triangle2D() {}

public:
	inline Triangle2D operator +  (const Vector2D& rhs) const
	{
		return Triangle2D(mPoints[0] + rhs, mPoints[1] + rhs, mPoints[2] + rhs);
	}
	inline const Triangle2D& operator += (const Vector2D& rhs)
	{
		mPoints[0] += rhs;
		mPoints[1] += rhs;
		mPoints[2] += rhs;
		return *this;
	}
	inline Triangle2D operator -  (const Vector2D& rhs) const
	{
		return Triangle2D(mPoints[0] - rhs, mPoints[1] - rhs, mPoints[2] - rhs);
	}
	inline const Triangle2D& operator -= (const Vector2D& rhs)
	{
		mPoints[0] -= rhs;
		mPoints[1] -= rhs;
		mPoints[2] -= rhs;
		return *this;
	}

	inline const Triangle2D& operator = (const Triangle2D& rhs)
	{
		mPoints[0] = rhs.mPoints[0];
		mPoints[1] = rhs.mPoints[1];
		mPoints[2] = rhs.mPoints[2];
		return *this;
	}

	inline const bool in(const Vector2D& p) const
	{
		return Math::pointInTri2D(p, mPoints[0], mPoints[1], mPoints[2]);
	}

//	inline const bool in(const Vector2D& p) const
//	{
//		float det12 = mPoints[1].crossProduct(mPoints[2]); //det(v1 v2)
//
//		float a = p.crossProduct(mPoints[2]) /* det(v v2) */ -  mPoints[0].crossProduct(mPoints[2]) /* det(v0 v2) */ / det12;
//		float b = -(p.crossProduct(mPoints[1]) /* det(v v1) */ - mPoints[0].crossProduct(mPoints[1]) /* det(v0 v1) */) / det12;
//
//		return (a > 0.f && b > 0.f) && ((a + b) < 1.f);
//	}

	inline const bool in(const Line2D& line) const
	{
		if(in(line.mPoints[0]) && in(line.mPoints[1]))
			return true;

		return false;
	}
	inline const bool in(const Triangle2D& tris) const
	{
		if(in(tris.mPoints[0]) && in(tris.mPoints[1]) && in(tris.mPoints[2]))
			return true;

		return false;
	}

	inline const bool intersects(const Line2D& line)
	{
		if(Line2D(mPoints[0], mPoints[1]).intersects(line))
			return true;

		if(Line2D(mPoints[1], mPoints[2]).intersects(line))
			return true;

		if(Line2D(mPoints[2], mPoints[0]).intersects(line))
			return true;

		return false;
	}

	const bool intersects(Triangle2D& tris)
	{
		tris.setLineIndex(0);
		Line2D* line = (Line2D*)tris.getNextLine();
		while(line)
		{
			if(intersects(*line))
				return true;

			line = (Line2D*)tris.getNextLine();
		}

		return false;
	}

};

#endif /* TRIANGLE2D_H_ */
